Skip to content

ChannelManager read refactor follow ups#4374

Open
joostjager wants to merge 5 commits intolightningdevkit:mainfrom
joostjager:chanmgr-read-2
Open

ChannelManager read refactor follow ups#4374
joostjager wants to merge 5 commits intolightningdevkit:mainfrom
joostjager:chanmgr-read-2

Conversation

@joostjager
Copy link
Contributor

@joostjager joostjager commented Feb 3, 2026

Followup commits to improve the readability and maintainability of the ChannelManager deserialization code.

@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Feb 3, 2026

👋 Thanks for assigning @valentinewallace as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@joostjager joostjager marked this pull request as ready for review February 3, 2026 13:25
@codecov
Copy link

codecov bot commented Feb 3, 2026

Codecov Report

❌ Patch coverage is 73.68421% with 15 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.02%. Comparing base (35ab03f) to head (b4429bb).
⚠️ Report is 13 commits behind head on main.

Files with missing lines Patch % Lines
lightning/src/ln/channelmanager.rs 73.68% 13 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4374      +/-   ##
==========================================
+ Coverage   85.99%   86.02%   +0.02%     
==========================================
  Files         156      156              
  Lines      102766   102844      +78     
  Branches   102766   102844      +78     
==========================================
+ Hits        88378    88471      +93     
+ Misses      11879    11863      -16     
- Partials     2509     2510       +1     
Flag Coverage Δ
tests 86.02% <73.68%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@valentinewallace valentinewallace left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Care to throw in any of these mentioned updates? #4332 (comment) Seems like a good opportunity

testing_dnssec_proof_offer_resolution_override: Mutex::new(new_hash_map()),
};

// Step 7: Replay pending claims and fail HTLCs.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my experience using step numbers in ldk-sample main, it's kinda annoying to have to update all of them when something changes. Maybe that's not as much of a risk here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it might help a bit with navigation in this huge function. In other languages one would quickly extract methods, but in my experience that isn't always in Rust. Would you prefer that? I can try it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't really prefer extracting methods. Just wanted to point it out, we can keep the numbers

Copy link
Contributor Author

@joostjager joostjager Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made it unnumbered headings

@ldk-reviews-bot
Copy link

👋 The first review has been submitted!

Do you think this PR is ready for a second reviewer? If so, click here to assign a second reviewer.

@joostjager
Copy link
Contributor Author

Care to throw in any of these mentioned updates? #4332 (comment) Seems like a good opportunity

Done

Copy link
Contributor

@valentinewallace valentinewallace left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice cleanups here!

Comment on lines 17832 to 17833
// consistency. Channels that are behind their monitors are force-closed. Channels without
// monitors (except those awaiting initial persistence) are rejected. Monitors without
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's true that channels without monitors will be rejected -- instead, we'll DecodeError::InvalidValue on the entire manager read. Were these comments added by Claude? I'm kinda not sold on them, they add to the review quite a bit and seem error prone/at risk of becoming out-of-date

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, clauded indeed. Unfortunate. First I went and corrected them, but I also felt what you mention about becoming out-of-date. In my opinion, there aren't enough comments in the code base, but comments that are located a bit further away from the code aren't ideal. Dropped the commit.

async_receive_offer_cache: AsyncReceiveOfferCache,
// Marked `_legacy` because in versions > 0.2 we are taking steps to remove the requirement of
// regularly persisting the `ChannelManager` and instead rebuild the set of HTLC forwards from
// `Channel{Monitor}` data. See [`ChannelManager::read`].
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think ChannelManager::read adds anything to the understanding of what's going on here, can probably remove that sentence

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this was pointing to the reconstruct boolean, but can't link that.

Copy link
Contributor Author

@joostjager joostjager Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed now, show references will get to the usage sites quickly enough. Can't link in // comments anyway.

.into_iter()
.zip(onion_fields)
.map(|((hash, htlcs), onion)| (hash, htlcs, onion))
.collect()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, we introduce an intermediate allocation here. Wonder if the whole creation of claimable_payments can move here, to avoid it? It feels somewhat fitting.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've considered that, but it would need the keys for the legacy handling branch. But perhaps that's ok? The distinction between stage 1 and 2 isn't carved in stone.

Copy link
Contributor Author

@joostjager joostjager Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the commit with this. It's seem better indeed.

.unwrap_or_else(new_hash_map),
inbound_payment_id_secret,
in_flight_monitor_updates,
in_flight_monitor_updates: in_flight_monitor_updates.unwrap_or_default(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this use HashMap::new() or new_hash_map (which I think is what we want)? CI seems fine though...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is the same?

HashMap::default() -> creates HashMap with RandomState::default() -> which calls RandomState::new() which is what new_hash_map does too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If true, we could replace all new_hash_map calls with HashMap::default(), to make it look slightly less custom.

joostjager and others added 5 commits February 5, 2026 10:23
Reorder the struct fields to place all three `_legacy` fields together
at the end, allowing the explanatory comment to appear once instead of
being duplicated three times.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Initialize pending_claiming_payments and monitor_update_blocked_actions_per_peer
with None and resolve with unwrap_or_else, matching the pattern used for other
optional hash map fields like pending_intercepted_htlcs_legacy.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Since there is no semantic difference between None and Some(empty vec)
for peer_storage_dir, simplify the type to Vec and use unwrap_or_default()
when reading from TLV fields.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Move the reconstruction of claimable_payments from the main
ChannelManager::read into ChannelManagerData::read. This removes
the separate claimable_htlc_purposes and claimable_htlc_onion_fields
fields from ChannelManagerData, replacing them with the combined
claimable_payments HashMap.

This requires adding a node_signer parameter to ChannelManagerDataReadArgs
to support verification of legacy hop data when reconstructing payment
purposes for very old serialized data (pre-0.0.107).

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Since there is no semantic difference between None and Some(empty map)
for in_flight_monitor_updates, simplify the type to HashMap and use
unwrap_or_default() when reading from TLV fields.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@joostjager
Copy link
Contributor Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants